package com.kaifamiao.session;

import com.kaifamiao.model.Configuration;
import com.kaifamiao.model.Mapper;
import com.kaifamiao.util.DBUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.List;
import java.util.Map;

/**
 * 1.获取数据库连接
 * 2.使用代理创建代理对象
 * 3.执行 sql
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * 获取数据库连接
     * @return
     */
    private Connection getConnection() {
        return DBUtils.createConnection(this.configuration.getDriver(),
                this.configuration.getUrl(),
                this.configuration.getUsername(),
                this.configuration.getPassword());
    }

    /**
     * 使用代理创建代理对象，用于执行 sql
     * @param clazz
     * @param <T>
     * @return
     */
    @Override
    public <T> T getMapper(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz},
                new MyInvocationHandler(getConnection(),configuration.getMappers()));
    }

    @Override
    public <T> List<T> selectList(String string) {
        // 获取最后一个 "."的位置
        int i = string.lastIndexOf(".");
        // 拿到 className
        String className = string.substring(0, i);
        // 拿到 methodName
        String methodName = string.substring(i + 1);
        try {
            // 创建 Class 对象
            Class clazz = Class.forName(className);
            Object object = Proxy.newProxyInstance(clazz.getClassLoader(),
                    new Class[]{clazz},
                    new MyInvocationHandler(getConnection(), configuration.getMappers()));
            MyInvocationHandler myInvocationHandler = new MyInvocationHandler(getConnection(), configuration.getMappers());
            Method[] methods = clazz.getDeclaredMethods();
            Object result = null;
            for (Method method : methods) {
                result = method.invoke(object, method.getParameters());
            }
            return (List<T>) result;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}

/**
 * 代理方式
 */
class MyInvocationHandler implements InvocationHandler{

    private Connection connection;

    private Map<String, Mapper> mappers;

    public MyInvocationHandler(Connection connection, Map<String, Mapper> mappers) {
        this.connection = connection;
        this.mappers = mappers;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // mappers key ===  className.methodName
        String methodName = method.getName();
        String className = method.getDeclaringClass().getName();
        // 根据键从 mappers 中获取 Mapper
        Mapper mapper = mappers.get(className + "." + methodName);
        // 从 mapper 中获取 sql 和 resultType
        String resultType = mapper.getResultType();
        String sql = mapper.getSql();
        // 执行 sql
        Object object = Execute.executeQuery(connection, sql, resultType, args);
        System.out.println("方法执行结束");
        return object;
    }
}
